#include "stdafx.h"
#include <XSprite.h>
#include <OpenGL\glew.h>
#include <OpenGL\freeglut.h>


XSprite::XSprite()
{	
	VertexBuffer = 0;
	IndexBuffer = 0;

	_initBuffers();
}

XSprite::~XSprite()
{
	_freeBuffers();
}

void XSprite::_initBuffers()
{
	_freeBuffers();

	XVertex vData[4];
	unsigned int iData[4];
	iData[0] = 0;
	iData[1] = 1;
	iData[2] = 2;
	iData[3] = 3;

	glGenBuffers( 1, &VertexBuffer);
	glBindBuffer( GL_ARRAY_BUFFER, VertexBuffer); 
	glBufferData( GL_ARRAY_BUFFER, 4 * sizeof(XVertex), vData, GL_DYNAMIC_DRAW ); 

	glGenBuffers( 1, &IndexBuffer); 
	glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, IndexBuffer); 
	glBufferData( GL_ELEMENT_ARRAY_BUFFER, 4 * sizeof(unsigned int), iData, GL_STATIC_DRAW ); 

	glBindBuffer( GL_ARRAY_BUFFER, NULL );
	glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, NULL );

}

void XSprite::_freeBuffers()
{
	if(VertexBuffer != 0)
	{
		glDeleteBuffers(1, &VertexBuffer);
		VertexBuffer = 0;
	}

	if(IndexBuffer != 0)
	{
		glDeleteBuffers(1, &IndexBuffer);
		IndexBuffer = 0;
	}
}

void XSprite::Draw(XRectangle pos)
{
	glBindBuffer(GL_ARRAY_BUFFER, VertexBuffer);

	if(!(pos == LastPosition))
	{
		XVertex* vData = new XVertex[4];
		vData[0].X = pos.X;
		vData[0].Y = pos.Y;
		vData[1].X = pos.X + pos.W;
		vData[1].Y = pos.Y;
		vData[2].X = pos.X;
		vData[2].Y = pos.Y + pos.H;
		vData[3].X = pos.X + pos.W;
		vData[3].Y = pos.Y + pos.H;

		glBufferData(GL_ARRAY_BUFFER, 4 * sizeof(XVertex), vData, GL_DYNAMIC_DRAW);

		delete[] vData;

		LastPosition = pos;
		LastClip.X = 0;
		LastClip.Y = 0;
		LastClip.W = 0;
		LastClip.H = 0;
	}

	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexBuffer);

	glEnableClientState(GL_VERTEX_ARRAY);
	glVertexPointer(2, GL_FLOAT, 0, NULL);
	glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_INT, NULL);

	glDisableClientState(GL_VERTEX_ARRAY);
	glBindBuffer(GL_ARRAY_BUFFER, NULL);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, NULL);
}

void XSprite::Draw(XRectangle pos, XTexture* tex)
{
	glBindBuffer(GL_ARRAY_BUFFER, VertexBuffer);
	
	if(!(LastPosition == pos))
	{
		XVertexData* vData = new XVertexData[4];
	
		vData[0].Position.X = pos.X;
		vData[0].Position.Y = pos.Y;
		vData[1].Position.X = pos.X + pos.W;
		vData[1].Position.Y = pos.Y;
		vData[2].Position.X = pos.X;
		vData[2].Position.Y = pos.Y + pos.H;
		vData[3].Position.X = pos.X + pos.W;
		vData[3].Position.Y = pos.Y + pos.H;

		vData[0].TextureCoord.X = 0;
		vData[0].TextureCoord.Y = 0;
		vData[1].TextureCoord.X = 1;
		vData[1].TextureCoord.Y = 0;
		vData[2].TextureCoord.X = 0;
		vData[2].TextureCoord.Y = 1;
		vData[3].TextureCoord.X = 1;
		vData[3].TextureCoord.Y = 1;

		glBufferData(GL_ARRAY_BUFFER, 4 * sizeof(XVertexData), vData, GL_DYNAMIC_DRAW);

		delete vData;

		LastPosition = pos;
		LastClip.X = 0;
		LastClip.Y = 0;
		LastClip.W = 0;
		LastClip.H = 0;
	}


	glBindTexture(GL_TEXTURE_2D, tex->ID);

	glEnableClientState(GL_VERTEX_ARRAY);
	glEnableClientState(GL_TEXTURE_COORD_ARRAY);

	glTexCoordPointer(2, GL_FLOAT, sizeof(XVertexData), (void*) offsetof(XVertexData, TextureCoord));
	glVertexPointer(2, GL_FLOAT, sizeof(XVertexData), (void*) offsetof(XVertexData, Position));

	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexBuffer);
	glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_INT, NULL);

	glDisableClientState(GL_VERTEX_ARRAY);
	glDisableClientState(GL_TEXTURE_COORD_ARRAY);

	glBindTexture(GL_TEXTURE_2D, NULL);
	glBindBuffer(GL_ARRAY_BUFFER, NULL);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, NULL);
}

void XSprite::Draw(XRectangle pos, XTexture* tex, XRectangle texClip)
{
	glBindBuffer(GL_ARRAY_BUFFER, VertexBuffer);

	if(!(LastPosition == pos || LastClip == texClip))
	{
		XVertexData* vData = new XVertexData[4];
	
		vData[0].Position.X = pos.X;
		vData[0].Position.Y = pos.Y;
		vData[1].Position.X = pos.X + pos.W;
		vData[1].Position.Y = pos.Y;
		vData[2].Position.X = pos.X;
		vData[2].Position.Y = pos.Y + pos.H;
		vData[3].Position.X = pos.X + pos.W;
		vData[3].Position.Y = pos.Y + pos.H;

		vData[0].TextureCoord.X = (float)texClip.X/tex->GetWidth();
		vData[0].TextureCoord.Y = (float)texClip.Y/tex->GetHeight();
		vData[1].TextureCoord.X = (float)(texClip.X + texClip.W)/tex->GetWidth();
		vData[1].TextureCoord.Y = (float)texClip.Y/tex->GetHeight();
		vData[2].TextureCoord.X = (float)texClip.X/tex->GetWidth();
		vData[2].TextureCoord.Y = (float)(texClip.Y + texClip.H)/tex->GetHeight();
		vData[3].TextureCoord.X = (float)(texClip.X + texClip.W)/tex->GetWidth();
		vData[3].TextureCoord.Y = (float)(texClip.Y + texClip.H)/tex->GetHeight();

		glBufferData(GL_ARRAY_BUFFER, 4 * sizeof(XVertexData), vData, GL_DYNAMIC_DRAW);

		delete[] vData;

		LastPosition = pos;
		LastClip = texClip;
	}

	glBindTexture(GL_TEXTURE_2D, tex->ID);

	glEnableClientState(GL_VERTEX_ARRAY);
	glEnableClientState(GL_TEXTURE_COORD_ARRAY);

	glTexCoordPointer(2, GL_FLOAT, sizeof(XVertexData), (void*) offsetof(XVertexData, TextureCoord));
	glVertexPointer(2, GL_FLOAT, sizeof(XVertexData), (void*) offsetof(XVertexData, Position));

	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexBuffer);
	glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_INT, NULL);

	glDisableClientState(GL_VERTEX_ARRAY);
	glDisableClientState(GL_TEXTURE_COORD_ARRAY);

	glBindTexture(GL_TEXTURE_2D, NULL);
	glBindBuffer(GL_ARRAY_BUFFER, NULL);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, NULL);
}

void XSprite::DrawString(XRectangle pos, XFont* font, std::string text)
{
	float dX = pos.X;
	float dY = pos.Y;

	glBindTexture(GL_TEXTURE_2D, font->ID);
	glEnableClientState(GL_VERTEX_ARRAY);
	glEnableClientState(GL_TEXTURE_COORD_ARRAY);

	glBindBuffer(GL_ARRAY_BUFFER, font->VertexBuffer);

	glTexCoordPointer(2, GL_FLOAT, sizeof(XVertexData), (void*) offsetof(XVertexData, TextureCoord));
	glVertexPointer(2, GL_FLOAT, sizeof(XVertexData), (void*) offsetof(XVertexData, Position));

	for( int i = 0; i < text.length(); ++i )
	{
		if(text[ i ] == ' ')
		{
			dX += font->Space;
		}

		else if(text[ i ] == '\n')
		{
			if(dY-pos.Y + font->NewLine < pos.H || pos.H == 0)
			{
				dY += font->NewLine;
				dX = pos.X;
			}
		}

		else if(dX-pos.X + font->Clips[(unsigned char)text[i]].W < pos.W || pos.W == 0)
		{
			unsigned int ascii = (unsigned char)text[i];

			glPushMatrix();
			glTranslatef(dX, dY, 0);

			glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, font->IndexBuffer[ascii]);
			glDrawElements(GL_QUADS, 4, GL_UNSIGNED_INT, NULL);

			dX += font->Clips[ascii].W+1;

			glPopMatrix();
		}
	}

	glDisableClientState(GL_VERTEX_ARRAY);
	glDisableClientState(GL_TEXTURE_COORD_ARRAY);

	glBindTexture(GL_TEXTURE_2D, NULL);
	glBindBuffer(GL_ARRAY_BUFFER, NULL);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, NULL);

}